package com.chu.cloud.service.impl;

import com.chu.cloud.dto.SeckillDto;
import com.chu.cloud.entity.Activity;
import com.chu.cloud.entity.Seckill;
import com.chu.cloud.enums.RedisKeyPrefix;
import com.chu.cloud.feign.client.IProductFeignClient;
import com.chu.cloud.repository.ActivityRepository;
import com.chu.cloud.repository.SeckillRepository;
import com.chu.cloud.response.ResponseMessage;
import com.chu.cloud.service.SeckillService;
import com.chu.cloud.util.BeanUtil;
import com.chu.cloud.util.ChuException;
import com.chu.cloud.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author: Tianshu.CHU
 * @Date: 2018/5/24 11:10
 * @Description:
 */
@Service
@Slf4j
public class SeckillServiceImpl implements SeckillService {

    @Autowired
    private SeckillRepository seckillRepository;

    @Autowired
    private ActivityRepository activityRepository;


    @Autowired
    private IProductFeignClient productFeignClient;

    private static final String SECKILL_REDUCE_INVENTORY_EVENT = "seckill.reduce.inventory.event";

    private final AtomicInteger num = new AtomicInteger(0);

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer save(Seckill seckill) {
        Activity activity = activityRepository.findOne(seckill.getActId());
        Date curTime = new Date();
        if (curTime.getTime() < activity.getSignStartTime().getTime() || curTime.getTime() > activity.getSignEndTime().getTime()) {
            throw new ChuException(String.format("该活动%s报名时间已经截止了", activity.getActType()));
        }

        if (seckill.getSeckillInventory().compareTo(activity.getSkuMaxNum()) > 0) {
            throw new ChuException("超出活动最大报名sku数,请尝试降低数量");
        }
        Seckill kill = seckillRepository.save(seckill);
        //活动锁库存
        ResponseMessage<Boolean> isEnoughInventory = productFeignClient.lockInventory(kill.getProductId(), kill.getSeckillInventory());
        if (isEnoughInventory.getCode() != 200 || !isEnoughInventory.getData()) {
            throw new ChuException(String.format("该商品%s没有足够的库存可参加活动,请补充库存", seckill.getProductId()));
        }
        Long expireTime = activity.getEndTime().getTime() - curTime.getTime();
        SeckillDto seckillDto = new SeckillDto();
        BeanUtil.copyProperties(seckillDto, kill);
        seckillDto.setStartTime(activity.getStartTime());
        seckillDto.setEndTime(activity.getEndTime());
        //按维度设置缓存
        String key = kill.getActId() + ":" + kill.getProductId();
        RedisUtil.set(RedisKeyPrefix.SECKILL_STOCKS, key, kill.getSeckillInventory(), expireTime.intValue());
        RedisUtil.set(RedisKeyPrefix.SECKILL, key, seckillDto, expireTime.intValue());
        RedisUtil.set(RedisKeyPrefix.SECKILL_PRICE, key, kill.getPrice(), expireTime.intValue());
        return kill.getId();
    }

    /**
     * 减库存
     *
     * @param productId
     * @param quantity
     * @param actId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean reduceInventory(Integer actId, Integer productId, Integer quantity) {
        //TODO 上redis锁
        log.info("当前执行请求:{}", num.incrementAndGet());
        Seckill seckill = Optional.ofNullable(seckillRepository.findByActIdAndProductId(actId, productId))
                                  .orElseThrow(() -> new ChuException("活动商品不存在"));
        int update = seckillRepository.reduceInventory(actId, productId, quantity);
        if (update == 1) {
            return true;
        }
        return false;
    }

}
